package io.gitee.lwq.encrypt.spring.boot.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.gitee.lwq.encrypt.spring.boot.annotation.Encrypt;
import io.gitee.lwq.encrypt.spring.boot.autoconfigure.properties.EncryptProperties;
import io.gitee.lwq.encrypt.spring.boot.common.Constants;
import io.gitee.lwq.encrypt.spring.boot.common.encrypt.EncryptMethodFactory;
import io.gitee.lwq.encrypt.spring.boot.common.encrypt.strategy.IEncryptStrategy;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;

/**
 * 对 responseBody 加密
 *
 * @author mx
 */
@ControllerAdvice
public class ResBodyAdvice implements ResponseBodyAdvice {
    @Resource
    private EncryptProperties config;

    @Override
    public boolean supports(MethodParameter methodParam, Class converterType) {
        //If the method has Encrypt Annotation
        Boolean isEncrypt = methodParam.getMethod().isAnnotationPresent(Encrypt.class);
        if(!isEncrypt){
            return Boolean.FALSE;
        }
        Encrypt annotation = methodParam.getMethod().getAnnotation(Encrypt.class);
        String method = getMethod(annotation.method());
        if(StrUtil.isBlank(method)){
            return Boolean.FALSE;
        }
        IEncryptStrategy encryptStrategy = EncryptMethodFactory.INSTANCE.getEncryptStrategy(method);
        return encryptStrategy.check();
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
                                  MediaType selectedContentType, Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        if (ObjectUtil.isEmpty(body)) {
            return body;
        }
        Encrypt encrypt = returnType.getMethod().getAnnotation(Encrypt.class);
        IEncryptStrategy encryptStrategy = EncryptMethodFactory.INSTANCE.getEncryptStrategy(getMethod(encrypt.method()));

        //header设置需要解密flag
        response.getHeaders().set(Constants.ENCRYPT_KEY, Constants.EncryptFlag.TRUE.name());
        return encryptStrategy.encryptBody(body, request);
    }

    private String getMethod(EncryptMethodFactory.EncryptMethodEnum method){
        return StrUtil.isNotBlank(method.getDesc())? method.name():config.getMethod();
    }
}
